﻿using Microsoft.Extensions.Logging;

namespace ThingsGateway.Application.Core;


/// <summary>
/// 驱动插件，继承实现不同PLC通讯
/// 约定构造函数参数为<see cref="ILogger"/>
/// 属性暴露使用<see cref="DevicePropertyAttribute"/>特性标识
/// 读取字符串，DateTime等等不确定返回字节数量的方法属性特殊方法，需使用<see cref="MethodAttribute"/>特性标识
/// 普通方法读写默认只支持基元类型<see cref="Type.IsPrimitive"/>
/// </summary>
public abstract class DriverBase : IDisposable
{
    protected ILogger _logger;

    public DriverBase(ILogger logger)
    {
        _logger = logger;
    }

    /// <summary>
    /// 采集驱动读取，支持PLC多读的，地址与长度转换为;分割
    /// </summary>
    /// <param name="deviceVariableSourceRead"></param>
    /// <returns></returns>
    public virtual async Task<Result<byte[]>> ReadSourceAsync(DeviceVariableSourceRead deviceVariableSourceRead)
    {
        if (deviceVariableSourceRead.Address.Contains(";") && deviceVariableSourceRead.Length.Contains(";"))
        {
            try
            {
                string[] address = deviceVariableSourceRead.Address.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                ushort[] length = deviceVariableSourceRead.Length.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries).
                    Select(m => ushort.Parse(m)).ToArray();
                Result<byte[]> read = await ReadBatchAsync(address, length);
                if (!read.IsSuccess)
                {
                    deviceVariableSourceRead.DeviceVariables.ForEach(it => it.Quality = 0);
                }
                return ReadWriteHelpers.DealWithReadResult(read, content =>
                ReadWriteHelpers.PraseStructContent(content, deviceVariableSourceRead.DeviceVariables,
                    ByteConverter));
            }
            catch (Exception ex)
            {
                deviceVariableSourceRead.DeviceVariables.ForEach(it => it.Quality = 0);
                return new Result<byte[]>("读取失败 长度[" + deviceVariableSourceRead.Length + "] 解析失败 : " + ex.Message);

            }
        }
        else
        {
            ushort length;
            if (!ushort.TryParse(deviceVariableSourceRead.Length, out length))
                return new Result<byte[]>("解析失败 长度[" + deviceVariableSourceRead.Length + "] 解析失败 :");
            Result<byte[]> read = await ReadAsync(deviceVariableSourceRead.Address, length);
            if (!read.IsSuccess)
            {
                deviceVariableSourceRead.DeviceVariables.ForEach(it => it.Quality = 0);
            }
            return ReadWriteHelpers.DealWithReadResult(read, content =>
            ReadWriteHelpers.PraseStructContent(content, deviceVariableSourceRead.DeviceVariables,
                ByteConverter));
        }
    }



    /// <summary>
    /// 数据转换器
    /// </summary>
    /// <returns></returns>
    public abstract IByteConverter ByteConverter { get; }
    /// <summary>
    /// 初始化
    /// </summary>
    /// <returns></returns>
    public abstract void Init(Device device);
    /// <summary>
    /// 结束通讯后执行的方法
    /// </summary>
    /// <returns></returns>
    public abstract void AfterStop();
    /// <summary>
    /// 开始通讯前执行的方法
    /// </summary>
    /// <returns></returns>
    public abstract void BeforStart();
    /// <summary>
    /// 返回是否支持读取
    /// </summary>
    /// <returns></returns>
    public abstract bool IsSupportAddressRequest();
    /// <summary>
    /// 连读分包，返回实际通讯包信息<see cref="DeviceVariableSourceRead"/> 
    /// <br></br>这部分每个驱动不一样，所以需要实现这个接口
    /// </summary>
    /// <param name="deviceVariables">设备下的全部通讯点位</param>
    /// <returns></returns>
    public abstract Result<List<DeviceVariableSourceRead>> LoadSourceRead(List<DeviceVariable> deviceVariables);
    /// <summary>
    /// 返回全部内容字节数组
    /// <br></br>
    /// 通常使用<see cref="IReadWrite.ReadAsync(string, ushort)"/>可以直接返回正确信息
    /// </summary>
    /// <param name="address">变量地址</param>
    /// <param name="length">读取长度</param>
    /// <returns></returns>
    protected abstract Task<Result<byte[]>> ReadAsync(string address, ushort length);
    /// <summary>
    /// PLC批量读取,需PLC支持
    /// <br></br>
    /// 大部分由<see cref="ReadAsync(string, ushort)"/>读取长字节后解析，如不支持批量读取，直接返回<see cref="Result{T}"/>
    /// </summary>
    /// <param name="address"></param>
    /// <param name="length"></param>
    /// <returns></returns>
    protected virtual Task<Result<byte[]>> ReadBatchAsync(string[] address, ushort[] length)
    {
        return Task.FromResult(new Result<byte[]>());
    }
    /// <summary>
    /// 写入变量值
    /// </summary>
    /// <param name="deviceVariable">变量实体</param>
    /// <param name="value">变量写入值</param>
    /// <returns></returns>
    public abstract Task<Result> WriteValueByNameAsync(DeviceVariable deviceVariable, string value);

    public abstract void Dispose();
}
